/**
 * @file kalloc.c
 * @date 23.04.26
 * @author xin
 * @brief 申请物理页面（allocator）以及释放
 * @version 0.1
 * @status Stable
*/

/* 暂时剔除kalloc()/kfree()/kinit()中用到锁的代码 */

#include "types.h"
#include "defs.h"
#include "riscv.h"
#include "memlayout.h"

/**
 * @brief 释放从pa_start到pa_end范围内的内存
 * @param pa_start 地址开始处
 * @param pa_end 地址结尾处
*/
void freerange(void *pa_start, void *pa_end);

// kernel后的第一个地址，在kernel.ld中定义
extern char end[];

// 运行时的页表
struct run {
    struct run *next;
};

// 内核可用的空闲页表
struct {
    struct run *freelist;
} kmem;

void *
kalloc(void)
{
    struct run *r;
    
    r = kmem.freelist;
    if (r) {
        kmem.freelist = r->next;
        memset((char*)r, 5, PGSIZE); //用无用的数据填充
    }
    return (void*)r;
}

void
kfree(void *pa)
{
    struct run *r;

    if (((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
        panic("kfree");

    memset(pa, 1, PGSIZE); // 使用全1填充以捕获悬垂引用

    r = (struct run*) pa;

    r->next = kmem.freelist;
    kmem.freelist = r;
}

void
freerange(void *pa_start, void *pa_end) 
{
    char *p;
    p = (char*)PGROUNDUP((uint64)pa_start);
    while (p + PGSIZE <= (char *)pa_end) {
        kfree(p);
        p += PGSIZE;
    }
}

void
kinit()
{
    freerange(end, (void*)PHYSTOP);
}
